﻿using System;
using System.Collections.Generic;
using System.Text;
using ET;
using Marx;
using Server;

namespace Demo
{
    [MessageHandler]
    public class LoginGateHandler : AMRpcHandler<LoginGateRequest, LoginGateResponse>
    {
        protected override async ETTask Run(Session session, LoginGateRequest request, LoginGateResponse response, Action reply)
        {
            session.OnGateLoginFinish();
            if(Host.Instance.GetHostState() != HostState.Running)
            {
                response.Error = ResultCode.ERR_LoginDenied;
                reply();
                return;
            }

            var gate = Host.GetScene(request.GateId);
            if(gate == null)
            {
                response.Error = ResultCode.ERR_LoginDenied;
                response.Message = "无效的gate id";
                reply();
                return;
            }

            var comp = gate.GetComponent<LoginTokenComponent>();
            var keyInfo = comp.Get(request.Token);
            if (keyInfo == null || keyInfo.Account != request.Account || !keyInfo.Players.Contains(request.PlayerId))
            {
                response.Error = ET.ErrorCore.ERR_ConnectGateKeyError;
                response.Message = "Gate key验证失败!";
                reply();
                return;
            }
            comp.Remove(request.Token);

            try
            {
                session.AddComponent<MailBoxComponent, MailboxType>(MailboxType.GateSession);
                session.AddComponent<SessionClientComponent>();
            }
            catch(Exception)
            {
                response.Error = ResultCode.ERR_Fail;
                reply();
                return;
            }

            var clientComponent = session.GetComponent<SessionClientComponent>();

            long instanceId = session.InstanceId;
            using (await CoroutineLockComponent.Instance.Wait(MarxCoroutineLock.Account, keyInfo.AccountId))
            {
                if(instanceId != session.InstanceId)
                {
                    response.Error = ResultCode.ERR_LoginDenied;
                    reply();
                    return;
                }

                string account = keyInfo.Account;
                var agent = ClientManager.Instance.Get(keyInfo.AccountId);
                if(agent != null)
                {
                    if(agent.Session == session)
                    {
                        reply();
                        return;
                    }

                    agent.CancelDestroy();
                    agent.SetSession(session);

                    if(agent.PlayerId != request.PlayerId)
                    {
                        await agent.DestroyPlayer();
                    }
                }
                else
                {
                    agent = new ClientAgent(account, keyInfo.AccountId);
                }

                var result = await gate.GetComponent<PlayerCreatorComponent>().CreatePlayer(keyInfo.LogicAppId, request.PlayerId, instanceId, agent);
                if (result != ResultCode.Success)
                {
                    Log.Error($"Create player failed: code [{result}]");
                    session.Dispose();
                    agent.SetSession(null);
                    return;
                }

                clientComponent.Agent = agent;
                ClientManager.Instance.Add(agent);

                response.PlayerId = request.PlayerId;
                reply();
            }
            Log.Info("---------------Login Gate Success--------------");
        }
    }


    [ActorMessageHandler]
    public class SSRegLoginTokenHandler : AMActorRpcHandler<Scene, SSRegLoginTokenRequest, SSRegLoginTokenResponse>
    {
        protected override async ETTask Run(Scene actor, SSRegLoginTokenRequest request, SSRegLoginTokenResponse response, Action reply)
        {
            long token = RandomHelper.RandInt64();
            actor.GetComponent<LoginTokenComponent>().Add(token, request.Account, request.AccountId, request.LogicAppId, request.Players);
            response.Token = token;
            reply();
            await ETTask.CompletedTask;
        }
    }
}
